﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PessModel;
using System.Web.Security;
using PessMvc.Models;
using PessMvc.Helpers;
using System.Data;
using System.IO;
using LinqToExcel;
using LinqToExcel.Domain;
using PessMvc.Lib;
using DoddleReport;
using DoddleReport.Web;
using System.Globalization;
using System.Resources;
using System.Collections;
using System.Configuration;
using System.Web.Script.Serialization;

namespace PessMvc.Controllers
{
    [Authorize]
    [NotNeedToChangePassword]
    public class ExpertJudgeController : Controller
    {
        PessModel.PESSEntities db;
        //
        // GET: /ExpertJudge/
        public ExpertJudgeController()
        {
            db = new PessModel.PESSEntities();
        }
        //public ActionResult Index()
        //{
        //    return View();
        //}
        /// <summary>
        /// Find all ExpertGroups, and then put them into a model.
        /// </summary>
        /// <param name="expertGroupID"></param>
        /// <returns></returns>
        private ExpertGroupSelectionModel FillGroupSelectionModel(int activityID)
        {
            //int activityID = db.ExpertGroups.Find(expertGroupID).Subject.ActivityID;
            var exptGroups = (from eg in db.ExpertGroups
                              where eg.Subject.ActivityID == activityID
                              select eg).ToList();
            ExpertGroupSelectionModel exptGroupSelectionModel = new ExpertGroupSelectionModel();
            foreach (var eg in exptGroups)
            {
                exptGroupSelectionModel.ExpertGroups.Add(new ExpertGroupModel() { Id = eg.ID, Name = eg.Callsign, LocalName = eg.Callsign, IsSelected = false, Value = "" });
            }
            return exptGroupSelectionModel;
        }


        [Authorize(Roles = "Admin,Chair")]
        public ActionResult CreateInGroup(int expertGroupID, int activityID)
        {
            ViewBag.ExpertGroupID = expertGroupID;

            ViewBag.ExpertGroupSelection = FillGroupSelectionModel(activityID);//exptGroupSelectionModel;

            //Generate Expert SerialNumber
            var group=db.ExpertGroups.Find(expertGroupID);
            //expert.SerialNumber = GetExpertSerialNumber(group.SubjectID);
            ExpertJudge expJudge = new ExpertJudge();
            expJudge.SerialNumber = GetExpertSerialNumber(group.Subject.ActivityID);

            ViewBag.ExpertGroupCallsign = group.Callsign;
            ViewBag.ActivityID = group.Subject.ActivityID;
            ViewBag.Gender = Utility.GenderSelectList(true);
            return View("Create",expJudge);
        }

        [Authorize(Roles = "Admin,Chair")]
        public ActionResult Create(int activityID)
        {
            //expert.SerialNumber = GetExpertSerialNumber(group.SubjectID);
            ExpertJudge expJudge = new ExpertJudge();
            expJudge.SerialNumber = GetExpertSerialNumber(activityID);

            ViewBag.ExpertGroupSelection = FillGroupSelectionModel(activityID);//exptGroupSelectionModel;
            ViewBag.ExpertGroupID = -1;
            //ViewBag.ExpertGroupCallsign = "";
            ViewBag.ActivityID = activityID;
            ViewBag.Gender = Utility.GenderSelectList(true);
            return View(expJudge);
        }

        [Authorize(Roles = "Admin,Chair")]
        [HttpPost]
        public ActionResult Create(ExpertJudge expert, List<ExpertGroupModel> expertGroups)
        {
            //expert.Password = "111111";
            if (ModelState.IsValid)
            {
                IExpertJudgeBL ibl = new ExpertJudgeBL();
                string errorMsg="";
                List<ExpertGroup> selectedExpertGroups = new List<ExpertGroup>();
                if(expertGroups!=null)
                { 
                    selectedExpertGroups = (from egm in expertGroups
                                           where egm.IsSelected == true
                                           select new ExpertGroup() {ID=egm.Id }).ToList();
                }

                if (ibl.Add(expert,selectedExpertGroups, out errorMsg) == true)
                {
                    return RedirectToAction("Index", "ExpertJudge");
                }
                else
                {
                    ModelState.AddModelError("", errorMsg);
                }
            }

            //ViewBag.ExpertGroupID = expert.ExpertGroupID;
            //var group = db.ExpertGroups.Find(expert.ExpertGroupID);
            //ViewBag.ExpertGroupCallsign = group.Callsign;
            ViewBag.ActivityID = int.Parse(ConfigurationManager.AppSettings["CurrentActivityID"]);
            ViewBag.Gender = Utility.GenderSelectList(expert.Gender);
            //ViewBag.ExpertGroupSelection = FillGroupSelectionModel(expertGroups.First().Id);//exptGroupSelectionModel;
            return View(expert);
        }

        [Authorize(Roles = "Admin,Chair")]
        [HttpPost]
        public ActionResult AddExpertJudges(HttpPostedFileBase file, int activityID)
        {
            // Verify that the user selected a file
            if (file != null && file.ContentLength > 0)
            {
                // extract only the fielname
                var fileName = Path.GetFileName(file.FileName);
                // store the file inside ~/App_Data/uploads folder
                var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
                file.SaveAs(path);


                var excel = new ExcelQueryFactory(path);
                //excel.FileName = ;
                excel.DatabaseEngine = DatabaseEngine.Ace;
                excel.AddMapping<ExpertJudgeModel>(m => m.ExpertGroupID, "GroupID");
                excel.AddMapping<ExpertJudgeModel>(m => m.RealName, "Real Name");
                excel.AddMapping<ExpertJudgeModel>(m => m.Email, "Email Address");
                excel.AddMapping<ExpertJudgeModel>(m => m.Password, "Initial Pwd");
                excel.AddMapping<ExpertJudgeModel>(m => m.Phone, "Phone");
                var members = from m in excel.Worksheet<ExpertJudgeModel>()
                              select m;

                string errorMsg = "";
                IExpertJudgeBL ibl = new ExpertJudgeBL();
                foreach (var x in members)
                {
                    if (ibl.IfExpertExists(x.ExpertGroupID, x.RealName) == false&&ibl.IfExpertGroupMatchesActivity(activityID,x.ExpertGroupID))
                    {
                        ExpertJudge expert = new ExpertJudge() { 
                            SerialNumber=CalculateSerialNumber(x.ExpertGroupID),
                            Email = x.Email,
                            ExpertGroupID = x.ExpertGroupID, 
                            RealName = x.RealName, 
                            Phone = x.Phone };
                        //IExpertJudgeBL modified to satisfy many to many relationship between Group and Judge.
                        //Need to be fixed later.
                        if (ibl.Add(expert,db.ExpertGroups.Where(g=>g.ID==expert.ExpertGroupID).ToList(), out errorMsg, x.Password) == false) //Once error is encounted, stop adding remaining experts. Show error message.
                        {
                            throw new Exception(errorMsg);                            
                        }
                    }
                }
            }

            // redirect back to the index action to show the form once again
            return RedirectToAction("Index", new { activityID = activityID });  
        }
        private string CalculateSerialNumber(int? expertGroupID)
        {
            return GetExpertSerialNumber(db.ExpertGroups.Find(expertGroupID).Subject.ActivityID);
        }
        //private string GetExpertSerialNumber(int? subjectID)
        //{
        //    int activityID = db.Subjects.Find(subjectID).ActivityID;

        //    int expertCount = (from e in db.ExpertJudges
        //                       where e.ExpertGroup.Subject.ID == subjectID && e.ExpertGroup.Subject.ActivityID == activityID
        //                       select e).Count();

        //    return string.Format("A{0}S{1}PW{2}", activityID, subjectID, expertCount);

        //}
        private string GetExpertSerialNumber(int? activityID)
        {
            //int activityID = db.Subjects.Find(subjectID).ActivityID;

            //int expertCount = (from e in db.ExpertJudges
            //                   where e.ExpertGroup.Subject.ID == subjectID && e.ExpertGroup.Subject.ActivityID == activityID
            //                   select e).Count();
            List<string> snlist=(from e in db.ExpertJudges 
                            //join g in db.ExpertGroups on e.ExpertGroupID equals g.ID
                            //join s in db.Subjects on g.SubjectID equals s.ID
                            //where s.ActivityID==activityID                            
                            select e.SerialNumber).ToList();
            int expertCount=snlist.Count==0?0:snlist.Max(t=>Convert.ToInt32(t));//.GroupBy(e=>e.SerialNumber).Count();
            decimal ab=Convert.ToDecimal(expertCount) / 1000;
            int a = (int)ab;
            int b = (int)((ab - a) * 1000);

            return string.Format("{0}{1}", activityID, Utility.FormatExpertCount(++b));

        }

        [Authorize(Roles = "Admin,Chair")]
        public ActionResult Index(int? expertGroupID)
        {
            //var experts=db.ExpertJudges.Where(e => e.ExpertGroup.Subject.ActivityID == activityID);
            var experts = db.ExpertJudges;

            var expertModels = experts.ToList().ToExpertJudgeModelList();
            //var expertModels = new List<ExpertJudgeModel>();            
            //foreach(var e in experts)
            //{
            //    expertModels.Add(e.ToExpertJudgeModel());
            //}

            ViewBag.ActivityID = int.Parse(ConfigurationManager.AppSettings["CurrentActivityID"]);
            //ViewBag.ExpertGroupID=new SelectList(db.ExpertGroups.Where(g=>g.Subject.ActivityID==activityID),"ID","Callsign");
            return View(expertModels);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="userName">SerialNumber</param>
        /// <returns></returns>
        [Authorize(Roles = "Admin,ExpertJudge,Chair")]
        public ActionResult Edit(string serialNumber, string returnUrl, int activityID)
        {
            if (Utility.IsCurrentUserExpertHimself(serialNumber) || Roles.IsUserInRole("Admin") || Roles.IsUserInRole("Chair"))
            {
                var expert = db.ExpertJudges.Find(serialNumber); expert.Email = Membership.GetUser(serialNumber).Email;
                ViewBag.Gender = Utility.GenderSelectList(expert.Gender);
                ViewBag.ReturnUrl = returnUrl;
                //Available expert groups under an activity.
                ExpertGroupSelectionModel selectionModel = FillGroupSelectionModel(activityID);//
                foreach (var g in selectionModel.ExpertGroups)
                {
                    if (expert.ExpertGroups.Select(eg => eg.ID).Contains(g.Id))
                    {
                        g.IsSelected = true;
                    }
                }
                ViewBag.ExpertGroupSelection = selectionModel;
                ViewBag.HideArchiveDetails = db.Activities.Find(activityID).HideArchiveDetails;
                ViewBag.ActivityID = activityID;
                return View(expert);
            }
            else
            {
                throw new Exception("Not authorized.");
            }
        }

        [Authorize(Roles = "Admin,ExpertJudge,Chair")]
        [HttpPost]
        public JsonResult Edit(ExpertJudge expertJudge, string returnUrl, List<ExpertGroupModel> expertGroups)
        {
            if (ModelState.IsValid)
            {
                //var expert=db.ExpertJudges.Find(expertJudge.SerialNumber);
                db.Entry(expertJudge).State = EntityState.Modified;
                //System.Diagnostics.Debug.WriteLine(expertJudge.ExpertGroups.Count);
                db.SaveChanges();
                db.Dispose();               
                
                //var seletedGroups = expertGroups.Where(eg => eg.IsSelected == true);
                //foreach (var g in seletedGroups)
                //{
                //    ExpertGroup group = db.ExpertGroups.Find(g.Id);
                //    if (!group.ExpertJudges.Contains(expertJudge))
                //    {
                //        group.ExpertJudges.Add(expertJudge);
                //    }
                //}
                //db.SaveChanges();

                var user = Membership.GetUser(expertJudge.SerialNumber);
                user.Email = expertJudge.Email;
                Membership.UpdateUser(user);

                db = new PESSEntities();
                expertJudge = db.ExpertJudges.Find(expertJudge.SerialNumber);
                //var seletedGroups = expertGroups.Where(eg => eg.IsSelected == true);
                if (expertGroups != null)
                {
                    foreach (var g in expertGroups)
                    {
                        ExpertGroup group = db.ExpertGroups.Where(eg => eg.ID == g.Id).FirstOrDefault();
                        if (g.IsSelected && !group.ExpertJudges.Contains(expertJudge))
                        {
                            //!group.ExpertJudges.Contains(expertJudge)
                            group.ExpertJudges.Add(expertJudge);
                        }
                        else if (g.IsSelected == false && group.ExpertJudges.Contains(expertJudge))
                        {
                            group.ExpertJudges.Remove(expertJudge);
                        }
                    }
                    db.SaveChanges();
                }

                //return Go2ReturnUrl(returnUrl);//Redirect(returnUrl);
                return Json(returnUrl, JsonRequestBehavior.AllowGet);

            }
            else
            {
                ViewBag.Gender = Utility.GenderSelectList(expertJudge.Gender);

                //return View(expertJudge);
                return Json(returnUrl, JsonRequestBehavior.AllowGet);
            }

        }


        public ActionResult Go2ReturnUrl(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
            {
                return Redirect(returnUrl);
            }
            else
            {
                //return RedirectToAction("Index", "Activity");
                //For the sake of fewer clicks. We let expert judges see archives after log on.
                int activityID=db.ExpertJudges.Find(User.Identity.Name).ExpertGroups.FirstOrDefault().Subject.ActivityID;
                HttpContext.Session.Add("ActivityID", activityID);
                return RedirectToAction("Index", "Archive", new  {ActivityID=activityID});
            }
        }

        [Authorize(Roles = "Admin,Chair")]
        public ActionResult Delete(string serialNumber, string returnUrl)
        {
            ExpertJudge expert = db.ExpertJudges.Find(serialNumber);
            ViewBag.ReturnUrl = returnUrl;
            if (expert == null)
            {
                return HttpNotFound();
            }
            return View(expert);
        }

        [Authorize(Roles = "Admin,Chair")]
        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(string serialNumber, string returnUrl)
        {
            ExpertJudge expert = db.ExpertJudges.Find(serialNumber);
            ViewBag.ReturnUrl = returnUrl;
            //int expertGroupID=(int)expert.ExpertGroupID;
            if (expert.Scores.Count!=0)
            {
                ModelState.AddModelError("", "Cannot delete this reviewer. This reviewer has review records. ");
            }
            else if (!Membership.DeleteUser(serialNumber))
            {
                ModelState.AddModelError("", "Cannot delete this user. Please contact system administrator.");
            }
            else if(expert.ExpertGroups.Count!=0)
            {
                ModelState.AddModelError("", "Cannot delete this reviewer. Remove the reviewer from all groups first.");
            }
            else
            {
                db.ExpertJudges.Remove(expert);
                db.SaveChanges();
                //return RedirectToAction("Details", "ExpertGroup", new {id=expertGroupID });
                return Go2ReturnUrl(returnUrl);
            }            
                
            return View(expert);            
        }

        [Authorize(Roles = "Admin,Chair")]
        [HttpPost]
        public ActionResult ExportToExcel(int activityID)
        {
            //var query = db.GetArchiveList(activityID).AsEnumerable();//db.Archives.Where(a => a.Subject.ActivityID == activityID);

            //return CreateReport(query,new DoddleReport.Writers.ExcelReportWriter(), selectedProperties);
            var query = db.GetExpertJudges(activityID);//db.ExpertJudges.Where(e => e.ExpertGroup.Subject.ActivityID == activityID);
            //var expertModels = experts.ToList().ToExpertJudgeModelList();
            //string subTitle = string.Format("{0}:{1}", subject != null ? subject.Name : "", activity.Name);
            var report = new DoddleReport.Report(query.ToReportSource());
            for (int i = 0; i < report.DataFields.Count; i++)
            {
                report.DataFields[i].HeaderText = Utility.Translate<PessResources.ExpertJudge>(report.DataFields[i].Name);
            }
            IReportWriter writer = new DoddleReport.Writers.ExcelReportWriter();
            return new ReportResult(report, writer, "application/vnd.ms-excel") { FileName = HttpUtility.UrlPathEncode("评委名单.xls") };
        }
       
    }
}
